<!-- Created by henian.xu on 2018/8/10. -->

<template>
    <div class="upload">
        <div
            :class="['item',`column-${column}`]"
            v-for="(item,index) in files"
        >
            <div
                class="inner"
                :style="`background-image: url('${item.blob||$defaultImg}');`">
                <div
                    class="del"
                    @click="onDel(item,index)"
                ><i class="f-icon">&#xf057;</i></div>

                <div
                    class="error"
                    v-if="item.error"
                >
                    <div
                        v-if="/(timeout|network)/.test(item.error)"
                        @click="onRetry(item)"
                    >点击重试
                    </div>
                    <i
                        class="f-icon tc-red fs-more"
                        v-else
                        @click="onRetry(item)"
                    >&#xf06a;
                    </i>
                </div>
                <div
                    class="progress"
                    v-else-if="item.active"
                >
                    <div class="inner"/>
                    <div class="label">{{ +item.progress }}%</div>
                </div>
            </div>
        </div>

        <div
            :class="['item','add',column&&`column-${column}`,{hide:isuploading}]"
            v-show="!maxFiles || maxFiles>files.length"
        >
            <!--:headers="$globalVar.reqHeaders"-->
            <vupload
                class="inner"
                ref="upload"
                name="file"
                :post-action="action"
                v-model="Vfiles"
                @input-filter="inputFilter"
                @input-file="inputFile"
                :size="size"
                :accept="accept"
            ><i class="f-icon">&#xf067;</i></vupload>
        </div>
    </div>
</template>

<script>
import emitter from '~/mixins/emitter';
import vueUploadComponent from 'vue-upload-component/dist/vue-upload-component.part.js';

export default {
    name: 'Upload',
    components: { vupload: vueUploadComponent },
    mixins: [emitter],
    data() {
        return {
            Vfiles: [],
            files: [],
        };
    },
    props: {
        value: {
            type: Array,
            default() {
                return [];
            },
        },
        action: {
            type: String,
            required: true,
        },
        size: {
            type: Number,
            default: 8 * 1024 * 1024,
        },
        accept: {
            type: String,
            default: undefined,
        },
        multiple: {
            type: Boolean,
            default: false,
        },
        maxFiles: {
            type: Number,
            default: undefined,
        },
        column: {
            type: Number,
            default: 0,
        },
    },
    computed: {
        isBlob() {
            const URL = window.URL || window.webkitURL;
            return !!(URL && URL.createObjectURL);
        },
        $$upload() {
            return this.$refs.upload;
        },
        filesMap() {
            return this.files.reduce((prev, curr, index) => {
                curr.__index = index;
                prev[curr.id] = curr;
                return prev;
            }, {});
        },
        isuploading() {
            return this.files.some(item => {
                return item.active;
            });
        },
        sizeName() {
            if (this.size < 1024) {
                return this.size + ' b';
            } else if (this.size < 1024 * 1024) {
                return this.size / 1024 + ' kb';
            } else if (this.size < 1024 * 1024 * 1024) {
                return this.size / 1024 / 1024 + ' mb';
            } else if (this.size < 1024 * 1024 * 1024 * 1024) {
                return this.size / 1024 / 1024 / 1024 + ' gb';
            }
        },
    },
    watch: {
        value(val) {
            if (!val || val.__innerCtrl) return;
            this.onClear();
            val.forEach(item => {
                this.files.push({
                    ...item,
                    blob: item.blob || item.address,
                });
            });
        },
    },
    methods: {
        onAddFile(file) {
            console.log('onAddFile', file);
            const URL = window.URL || window.webkitURL;
            if (URL && URL.createObjectURL) {
                file.blob = URL.createObjectURL(file.file);
            }
            if (this.filesMap[file.id]) {
                this.updateFile({ ...file });
            } else {
                this.files.push({ ...file });
            }
        },
        onUploadStart(file) {
            console.log('onUploadStart');
            this.updateFile(file);
        },
        onProgress(file) {
            console.log('onProgress');
            this.updateFile(file);
        },
        onError(file) {
            console.log('onError', file);
            this.updateFile(file);
        },
        onSuccess(file) {
            console.log('onSuccess');
            this.updateFile(file);
            this.updateValue();
        },
        updateFile(file) {
            const mapItem = this.filesMap[file.id];
            const __index = mapItem.__index;
            this.files.splice(__index, 1, file);
        },
        updateValue() {
            const val = [];
            this.files.forEach(item => {
                const { success, response, blob } = item;
                const { name, address } = response ? response.data : item;
                // if (!success) return;
                val.push({
                    name,
                    address,
                    blob,
                });
            });
            val.__innerCtrl = true;
            this.$emit('input', val);
            this.dispatch('formItem', 'x.form.change', [val]);
        },
        onDel(item, index) {
            if (item.active) {
                this.$$upload.update(item, { active: false });
            }
            this.files.splice(index, 1);
            this.updateValue();
        },
        onClear() {
            const { files, $refs } = this;
            if ($refs.upload) {
                files.forEach(item => {
                    if (!item.active) return;
                    $refs.upload.remove(item);
                });
            }
            files.splice(0, files.length);
        },
        onRetry(item) {
            // 内置的错误标识 size, extension, abort, server, denied, timeout, network
            // 可重试的 错误
            if (/(timeout|network)/.test(item.error)) {
                this.$$upload.add({
                    id: item.id,
                    file: item.file,
                    name: item.name,
                    size: item.size,
                });
                return;
            }
            switch (item.error) {
                case 'size':
                    this.$messageBox.tips(`超过指定大小(${this.sizeName})`);
                    break;
                case 'extension':
                    this.$messageBox.tips('文件类型错误');
                    break;
                case 'abort':
                    this.$messageBox.tips('用户终止');
                    break;
                case 'server':
                case 'denied':
                    this.$messageBox.tips('服务器错误，请联系管理员');
                    break;
            }
        },
        // 上传组件事件
        inputFilter(/*newFile, oldFile, prevent*/) {},
        inputFile(newFile, oldFile) {
            const { onAddFile, onUploadStart, onProgress, onError, onSuccess } = this;
            if (newFile && !oldFile) {
                // 添加文件
                onAddFile(newFile);
            }

            // 更新文件
            if (newFile && oldFile) {
                // 开始上传
                if (newFile.active && newFile.active !== oldFile.active) {
                    onUploadStart(newFile);

                    // 限定最小字节
                    // if (newFile.size >= 0 && newFile.size < 100 * 1024) {
                    //     newFile = this.$refs.upload.update(newFile, {error: 'size'});
                    // }
                }

                // 上传进度
                if (newFile.progress !== oldFile.progress) {
                    onProgress(newFile);
                }

                // 上传错误
                if (newFile.error !== oldFile.error) {
                    onError(newFile, newFile.error);
                }

                // 上传成功
                if (newFile.success !== oldFile.success) {
                    onSuccess(newFile, newFile.success);
                }
            }

            // 删除文件
            if (!newFile && oldFile) {
                // 自动删除 服务器上的文件
                if (oldFile.success && oldFile.response.id) {
                    // $.ajax({
                    //   type: 'DELETE',
                    //   url: '/file/delete?id=' + oldFile.response.id,
                    // });
                }
            }

            // 自动上传
            if (Boolean(newFile) !== Boolean(oldFile) || oldFile.error !== newFile.error) {
                if (!this.$$upload.active) {
                    this.$$upload.active = true;
                }
            }
        },
    },
    beforeDestroy() {
        this.onClear();
    },
};
</script>

<style lang="scss">
@import '~/assets/style/_index.scss';

.upload {
    flex: 1 1 auto;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: wrap;
    padding: $padding/2;
    /*background-color: #fff;*/

    > .item {
        flex: 0 0 auto;
        width: 100%;
        line-height: 0;
        padding: $padding/2;

        @for $i from 1 through 10 {
            &.column-#{$i} {
                width: 100% / $i;
            }
        }

        > .inner {
            line-height: $line-height;
            background-position: center;
            background-repeat: no-repeat;
            background-size: cover;
            box-shadow: 0 5px 10px 0 $gray9;

            position: relative;
            width: 100%;
            height: 0;
            padding-top: 50%;
            padding-bottom: 50%;
            border-radius: 5px;

            > .del {
                position: absolute;
                z-index: $z-index-2;
                top: -10px;
                right: -10px;
                color: $color-red;
                font-size: 20px;
                line-height: 20px;
                width: 20px;
                text-align: center;
                border-radius: 50%;
                background-color: #fff;
            }

            > .progress {
                position: absolute;
                z-index: 100;
                top: 0;
                right: 0;
                bottom: 0;
                left: 0;
                border-radius: 5px;
                background: rgba(0, 0, 0, 0.5);
                > .inner {
                    position: absolute;
                    top: 50%;
                    left: 50%;
                    width: 80px;
                    height: 80px;
                    margin-top: -40px;
                    margin-left: -40px;
                    box-sizing: border-box;
                    border: solid 5px transparent;
                    border-top-color: $color-main;
                    border-left-color: $color-main;
                    border-radius: 50%;

                    animation: nprogress-spinner 400ms linear infinite;
                }
                > .label {
                    position: absolute;
                    top: 0;
                    right: 0;
                    bottom: 0;
                    left: 0;
                    display: flex;
                    flex-direction: row;
                    justify-content: center;
                    align-items: center;
                    color: #fff;
                }
            }
            > .error {
                position: absolute;
                z-index: 200;
                top: 0;
                right: 0;
                bottom: 0;
                left: 0;
                border-radius: 5px;
                background: rgba(0, 0, 0, 0.5);
                display: flex;
                flex-direction: row;
                justify-content: center;
                align-items: center;
                color: #fff;
            }
        }
        &.add {
            > .inner {
                display: flex;
                flex-direction: row;
                justify-content: center;
                align-items: center;
                border: 1px solid $color-border;
                background-color: #fff;
                box-shadow: none;
                position: relative;
                overflow: hidden;
                input[type='file'] {
                    opacity: 0;
                    font-size: 20em;
                    z-index: 1;
                    top: 0;
                    left: 0;
                    right: 0;
                    bottom: 0;
                    position: absolute;
                    width: 100%;
                    height: 100%;
                }
                &:before {
                    display: inline-block;
                    content: '';
                    width: 0;
                    height: 0;
                    padding-top: 100%;
                    vertical-align: middle;
                }
                > .f-icon {
                    vertical-align: middle;
                    color: $gray6;
                    font-size: 18px;
                }
            }

            &.hide {
                position: relative;
                left: -200vw;
            }
        }
    }
}

.success {
    .upload > .item.add > .inner {
        border-color: $color-success;
    }
}
.error {
    .upload > .item.add > .inner {
        border-color: $color-danger;
    }
}
</style>
